#include "LoopScheduler.h"

#include <cstring>

#include "LoopControlInfoManager.h"
#include "GuiContext.h"
#include "CommandExecutor.h"
#include "CommandDispatcher.h"


LoopScheduler::LoopScheduler() : mloopManager(LoopManagerSingleton::instance()), mtaskScheduler(TaskSchedulerSingleton::instance())
    , mloopControlInfoManager(LoopControlInfoManagerSingleton::instance()), mtimedLoopCommandManager(TimedLoopCommandManagerSingleton::instance())
    ,  mpool(GuiContextSingleton::instance().getWorkPool()) {


    const DateTimeUtility::ClockTime_t timeOfDay = std::chrono::system_clock::now().time_since_epoch();

    const DateTimeUtility::ClockTime_t beginOfDay = timeOfDay - timeOfDay % DateTimeUtility::TICK_COUNT_OF_DAY;
    const DateTimeUtility::ClockTime_t endOfDay = beginOfDay + DateTimeUtility::TICK_COUNT_OF_DAY;


    TaskRecordPtr pTaskRecord(new TaskRecord(TaskletInfo{std::bind(&LoopScheduler::dailyCheck, this), nullptr}, endOfDay, DateTimeUtility::TICK_COUNT_OF_DAY, ETT_CIRCLE));
    mtaskScheduler.addTask(pTaskRecord);

    CommandDispatcherSingleton::instance().mnetworkListeners.push_back(this);
}



LoopScheduler::~LoopScheduler() {
    //dtor
}


void LoopScheduler::dailyCheck() {
    LOG_DEDUG("do daily work");
    if (0 == DateTimeUtility::getTime().tm_yday) {
        std::string result;
        CommandExecutorSingleton::instance().onDeleteLocalSwitch(result);
    }

}



void LoopScheduler::scheduleOffline(const bool loadPrevControlInfo) {
    mloopControlInfoManager.clear();
    std::shared_ptr<LoopControlInfoList> loopControlInfos(new LoopControlInfoList());

    bool offlineCommandExists = true;
    DateTimeUtility::ClockTime_t now = std::chrono::system_clock::now().time_since_epoch();
    if (!mloopControlInfoManager.load(now)) {
        offlineCommandExists = false;
    } else {
        mloopControlInfoManager.load(now, loadPrevControlInfo, *loopControlInfos);
        if (loopControlInfos->empty()) {
            offlineCommandExists = false;
        }
    }

    if (false == offlineCommandExists){
        const DateTimeUtility::ClockTime_t dayTime = now % DateTimeUtility::TICK_COUNT_OF_DAY;
        LoopControlInfoPtr ploopControlInfo = mtimedLoopCommandManager.load(dayTime);
        if (ploopControlInfo) {
            const DateTimeUtility::ClockTime_t beginOfDay = now - dayTime;
            ploopControlInfo.reset(new(ploopControlInfo->length) LoopControlInfo(*ploopControlInfo), LoopControlInfo::releaseMemory);
            ploopControlInfo->beginTime += beginOfDay;
            loopControlInfos->emplace_front(ploopControlInfo);
        } else {
//            LoopControlInfoList& allLoopControlInfos = mloopControlInfoManager.getLoopControlInfos();
//            if (!allLoopControlInfos.empty()) {
//                loopControlInfos->emplace_back(allLoopControlInfos.back());
//            }
        }
    }

    Task* pTask = buildDynamicFunctor(&LoopScheduler::commitLoopCommandTask, this, loopControlInfos);
    mpool->pushPool(pTask);

}



void LoopScheduler::commitLoopCommandTask(std::shared_ptr<LoopControlInfoList> ploopControlInfos, const Task* pTask) {
    LoopControlInfoList& loopControlInfos = *ploopControlInfos;
    if (ploopControlInfos->empty()) {
        mloopManager.closeAutoLoopStatus(LoopCommandType::WEAK_CLOSE_COMMAND, nullptr);
    } else {
        TaskRecordPtr pTaskRecord;

        LoopControlInfoList::iterator end = loopControlInfos.end();
        for (LoopControlInfoList::iterator iterator = loopControlInfos.begin(); iterator != end; ++iterator) {
            LoopControlInfoPtr& pLoopControlInfo = *iterator;
            //       TaskletInfo taskletInfo{mdoCommandCallback, nullptr};
            switch (pLoopControlInfo->commandType) {
            case LoopCommandType::TIMED_COMMAND: {
                pTaskRecord.reset(new TaskRecord(TaskletInfo{std::bind(&LoopManager::closeAutoLoopStatus, &mloopManager, LoopCommandType::TIMED_COMMAND, std::placeholders::_1), nullptr}, pLoopControlInfo->beginTime + pLoopControlInfo->duration));

                addTaskRecord(pTaskRecord);
            }
            case LoopCommandType::OFFLINE_COMMAND: {//
                std::stringstream sstream;
                sstream << *pLoopControlInfo;
                LOG_DEDUG("LoopControlInfo push to taskScheduler:%s", sstream.str().data());
                pTaskRecord.reset(new TaskRecord(TaskletInfo{std::bind(&LoopScheduler::doLoopCommand, this, pLoopControlInfo, std::placeholders::_1), nullptr}, pLoopControlInfo->beginTime));

                addTaskRecord(pTaskRecord);
            }
            break;


            case LoopCommandType::ONLINE_COMMAND: {
            }
            default: {
                LOG_ERROR("无效的离线/定时指令!");
            }
            break;

            }
        }
    }
    releaseDynamicFunctor(pTask);
}



void LoopScheduler::doLoopCommand(LoopControlInfoPtr pLoopControlInfo, void* data) {
    std::stringstream sstream;
    sstream << *pLoopControlInfo;
    LOG_DEDUG("taskScheduler call LoopControlInfo:%s", sstream.str().data());

    mloopManager.changeAutoLoopStatus(pLoopControlInfo);
}



void LoopScheduler::online(INetwork* const network) {
    msystemStatus = SystemStatus::ONLINE;

    LOG_WARN("system online, clean all offline and timed command...");

    clear();

//    std::string result;
//    CommandExecutorSingleton::instance().onDeleteLocalSwitch(result);
}







